﻿// Inner Fire 游戏引擎库
// AnimationBlend - 混合动画
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于保存项目的混合动画
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-04-30

#include "animation_blend.h"
#include <enum_parser.h>
#include <game/animation/animation.h>
#include <game/resource/assets.h>

namespace ifire::game {

AnimationBlendItem::AnimationBlendItem(const ikit::XmlNode& node)
    : value(node("Value")), clip(node.Value()) {}

const AnimationClip* AnimationBlendItem::GetClip() const { return clip.get(); }

void AnimationBlendItem::Setup() {
  clip.set(Assets::GetInstance().GetClip(clip.name, false));
}

void AnimationBlendItem::Ready() const { clip.get()->Ready(); }

AnimationBlend::AnimationBlend(Assets* manager, const ikit::XmlNode& node)
    : Resource(manager, node("Name"))
    , is_humanoid(node("IsHumanoid"))
    , is_root_motion(node("IsRootMotion")) {
  node.ReadItems("Ray", rays_);
  // rays_.reserve(node.GetCount("Ray"));
  // node.Foreach("Ray", [this](ikit::XmlNode& n, int) //
  //     { rays_.emplace_back(n); });
}

void AnimationBlend::Ready() {
  for (auto& e : rays_) {
    // 使每一个CLIP的项目都Ready
    for (auto& i : e.items) {
      i.Ready();
    }
  }
}

void AnimationBlend::Setup() {
  for (auto& e : rays_) {
    // 使每一个CLIP的项目都Ready
    for (auto& i : e.items) {
      i.Setup();
    }
  }
}

AnimationBlendRay& AnimationBlend::GetRay(int index) {
  // TODO: 在此处插入 return 语句
  return rays_[index];
}

AnimationBlendRay::AnimationBlendRay(const ikit::XmlNode& node) {
  node.ReadItems("Clip", items);
}

void AnimationBlendRay::Calculate(
    float weight_value, BlendItemWeight& a, BlendItemWeight& b) {

  // 特殊处理，当weight_value大于和小于项目时。仅返回一个项目。
  if (weight_value <= 0.01f) {
    SetOnly(items[0], a, b);
    return;
  } else if (weight_value >= 0.99f) {
    SetOnly(items.back(), a, b);
    return;
  }

  // 默认的项目
  size_t index_a = 0;
  size_t index_b = 1;

  // 项目是从1开始的，位于0位置的Value必然为0。
  for (size_t i = 1; i < items.size(); i++) {
    auto& item = items[i];
    // 当Value比weight大的时候，表示可以处于右边
    if (item.value >= weight_value) {
      index_b = i;
      index_a = i - 1;
      break;
    }
  }

  // 设置两者的CLIP
  a.clip = items[index_a].clip.get();
  b.clip = items[index_b].clip.get();

  // 得到两者之间的距离
  float distance_a = weight_value - items[index_a].value;
  float distance_b = items[index_b].value - weight_value;
  float total_distance = distance_a + distance_b;

  // 通过距离设置weight
  a.weight = distance_a / total_distance;
  b.weight = distance_b / total_distance;
}

void AnimationBlendRay::SetOnly(
    AnimationBlendItem& item, BlendItemWeight& a, BlendItemWeight& b) {
  a.weight = 1.0f;
  a.clip = item.clip.get();
  b.weight = 0.0f;
  b.clip = nullptr;
}

} // namespace ifire::game